package utils

import (
	"fmt"
	"io/fs"
	"os"
	"path/filepath"
	"strings"
	"unsafe"

	"gitee.com/u-language/u-language/ucom/enum"
)

var Debug = false

var zeroPtr unsafe.Pointer

// MustErr 对于非空错误，panic
func MustErr(err error) {
	if err != nil {
		panic(err)
	}
}

func Deferfunc() {
	err := recover()
	if err != nil {
		if Debug {
			panic(err)
		} else {
			fmt.Println("程序发生不可恢复的错误")
			os.Exit(2)
		}
	}
}

// IsNil 判断接口存储的值是否为nil
func IsNil(n interface{}) bool {
	type Iface struct {
		typ, data unsafe.Pointer
	}
	ni := (*Iface)((unsafe.Pointer)(&n))
	return ni.data == unsafe.Pointer(uintptr(zeroPtr))
}

// Is_In_AutoFree 返回是否是在自动释放块内函数
func Is_In_AutoFree(name string) bool {
	return strings.HasSuffix(name, enum.AutoFreeInFunc)
}

// MoveFile 实现移动文件
func MoveFile(oldname, newname string) error {
	return moveFile(oldname, newname)
}

// FindU 寻找目录下的U文件
func FindU(dir string) ([]string, error) {
	paths := make([]string, 0)
	err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
		if err != nil { //有错误返回
			return fmt.Errorf("path=%s \t err=%w", path, err)
		}
		if d.IsDir() && dir != path { //跳过目录
			return fs.SkipDir
		}
		if filepath.Ext(path) == ".u" { //只将扩展名为.u的视为源代码文件
			paths = append(paths, path)
		}
		return nil
	})
	return paths, err
}

// IsNoType 判断是否不是类型
func IsNoType(kind enum.Symbol) bool {
	return kind != enum.SymbolStruct && kind != enum.SymbolEnum && kind != enum.SymbolFunc && kind != enum.SymbolGenInst
}

// Typ_is_equal 判等两个类型是否相等
func Typ_is_equal(src1 string, src2 string) bool {
	if src1 != src2 {
		return is_ptr_and_nil(src1, src2)
	}
	return true
}

// is_ptr_and_nil 判等两个类型是否分别是指针和nil
func is_ptr_and_nil(src1, src2 string) bool {
	if src1 == enum.Nil && IsPtr(src2) {
		return true
	}
	if src2 == enum.Nil && IsPtr(src1) {
		return true
	}
	return false
}

// IsPtr 判断类型是不是指针类型
func IsPtr(typ string) bool {
	return typ[0] == '&' || typ == enum.UnsafePointer
}
